home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / std / c / 397 < prev    next >
Text File  |  1996-08-06  |  7KB  |  163 lines

  1. Path: solon.com!not-for-mail
  2. From: msb@sq.com
  3. Newsgroups: comp.std.c,comp.lang.c.moderated
  4. Subject: Re: Integral promotion.
  5. Date: 15 Feb 1996 08:44:06 -0600
  6. Organization: SoftQuad Inc., Toronto, Canada
  7. Sender: clc@solutions.solon.com
  8. Approved: clc@solutions.solon.com
  9. Message-ID: <4fvgrm$dv9@solutions.solon.com>
  10. References: <4fstj7$2l6@solutions.solon.com> <4fu835$9de@solutions.solon.com>
  11. NNTP-Posting-Host: solutions.solon.com
  12.  
  13. Oh dear, I have to correct Chris Torek (torek@bsdi.com).  Most of his
  14. article was correct, of course; please review it if you need more context.
  15.  
  16. The question was about
  17.  
  18. > > short test(short x1, short x2)
  19. > > {
  20. > >     short result;
  21. > >     result = x1 + x2;  /* Warning:  '=' : conversion from 'int '
  22. > >                           to 'short ', possible loss of data */
  23. > >     return result;
  24. > > }
  25.  
  26. Chris writes:
  27.  
  28. > For efficiency and/or less-surprising behavior, ANSI C says that
  29. > prototyped parameters (as you have here) are not promoted.  (Many
  30. > compilers simply promote them at the caller, and then narrow them
  31. > before entering the function, just as for Old C, but they can now
  32. > avoid these steps in this case.)
  33.  
  34. It is correct that prototyped arguments do not undergo the default
  35. *argument* promotions, but they still undergo the *integral* promotions.
  36. Thus even in ANSI C, if this function is called this way:
  37.  
  38.     extern short p, q, r, test(short,short);
  39.     r = test(p,q);
  40.  
  41. the values from p and q are still converted from short to int and back
  42. to short.  However, there is a difference from old C.  In old C, what
  43. happened was that p and q were converted to int in the caller, two ints
  44. were given to test(), and these int values were *then* converted back to
  45. shorts to assign them to x1 and x2.  In ANSI C, with the prototype in
  46. scope, p and q are converted to int and then *immediately* back to
  47. short; two shorts are passed to test(), and these values are assigned
  48. to x1 and x2.
  49.  
  50. And this difference is significant, because the caller and test() may
  51. be compiled separately.  This means that in old C, the compiler would
  52. *have* to perform the conversions; but in ANSI C, because the conversion
  53. is reversed within the same expression, it is trivial for the compiler
  54. to optimize it out.
  55.  
  56. In the code originally posted, the call was test(1,2).  Since the
  57. arguments in this case are ints, a conversion is always required.
  58.  
  59.  
  60. This is different from the case of an argument of type float.  In old C,
  61. just as shorts were automatically promoted to int anywhere, so floats
  62. were to double.  In ANSI C, *this* automatic promotion has been completely
  63. removed -- except when it forms part of the default argument promotions.
  64.  
  65. This paragraph of Chris's is worth reemphasizing:
  66.  
  67. > Because ANSI C requires promotion for non-prototypes and non-promotion
  68. > for prototypes, it is important to make sure you never mix up the
  69. > two kinds of declarations and definitions when you use `narrow'
  70. > types (char, short, signed char, unsigned char, unsigned short,
  71. > and float).
  72.  
  73.  
  74. Now to the inside of the function.
  75.  
  76. >     result = x1 + x2;
  77.  
  78. > ... if `int' and `short' are the same width, a result that would
  79. > be outside the range [SHRT_MIN .. SHRT_MAX] is also outside the
  80. > range [INT_MIN .. INT_MAX], and the behavior is undefined (ANSI C
  81. > section 3.3, p. 39, ll. 15--17).
  82.  
  83. Right.  If int and short are the same width, overflow can occur, with
  84. underfined behavior.
  85.  
  86. > On the other hand, if `int's are wider than `short's ... the sum is
  87. > not outside the representable range ...  The final step is to convert
  88. > the sum back to type `short'.  Here things get a little fuzzy....
  89.  
  90. No, they don't.
  91.  
  92. > comp.std.c has had arguments as to what happens if the sum is `int', 
  93. > `int' is wider than `short', and the sum is not representable as a `short'.
  94.  
  95. Only arguments between -- to be blunt -- people who know what they are
  96. talking about and those who do not.  Needless to say, Chris is usually
  97. in the former category, but not this time.  The result of the conversion
  98. in this case is implementation-defined, and undefined behavior does not
  99. occur.  Chapter and verse below.
  100.  
  101. > The Standard distinguishes between `implicit' and `explicit'
  102. > conversions ...
  103.  
  104. It makes no distinction whatever between their semantics, except that in
  105. certain cases "that involve pointers" (quote from 6.3.4/3.3.4), it requires
  106. the conversions to be explicit.  We're not talking about pointers here.
  107.  
  108. > Some have argued that an explicit conversion should never cause an
  109. > overflow, but there seems to be no wording in the standard to justify
  110. > this position.  There appears to be agreement that implicit conversion
  111. > might overflow.  The behavior on overflow would be undefined.
  112.  
  113. Completely wrong, assuming that "overflow" is meant to imply an error
  114. condition.  It might be sensible, but it's not what the standard specifies.
  115. Chapter and verse below.
  116.  
  117. > It is interesting, however, to note that if overflow will ever occur,
  118. > it will occur no matter whether the ranges of short and int coincide
  119. > or not.  The only thing that changes here is the exact operation that
  120. > overflows: the sum, or the implicit conversion in the assignment.
  121.  
  122. This would be correct if "overflow" is *not* taken as implying an error
  123. condition, but merely the occurrence of a value that will not fit.
  124.  
  125.  
  126. Excerpts from the standard:
  127.  
  128. *  From 6.3.16.1/3.3.16.1:
  129.  
  130. #  In "simple assignment" (=), the value of the right operand is
  131. #  converted to the type of the left operand ...
  132.  
  133. *  From 6.2.1.2/3.2.1.2:
  134.  
  135. #  When a value with integral type is demoted to a signed integer with
  136. #  smaller size ... if the value cannot be represented the result is
  137. #  implementation-defined.
  138.  
  139. Hence implementation-defined behavior occurs.
  140.  
  141. *  From 3.10/1.6 (emphasis added):
  142.  
  143. #  Implementation-defined behavior -- behavior, for a CORRECT program
  144. #  construct and CORRECT data, that depends on the characteristics of
  145. #  the implementation and that each implementation shall document.
  146.  
  147. *  From 3.16/1.6 (emphasis added):
  148.  
  149. #  Undefined behavior -- behavior, upon use of a NONPORTABLE OR ERRONEOUS
  150. #  program construct, of ERRONEOUS data, or of indeterminately-valued
  151. #  objects, for which the Standard imposes no requirements. ...
  152.  
  153. Hence implementation-defined and undefined behavior are mutually
  154. exclusive; the occurrence of implementation-defined behavior implies
  155. that the construct is correct; and so, in the case in question where
  156. int is wider than short, undefined behavior cannot occur.
  157. -- 
  158. Mark Brader                     "Nicely self-consistent. (Pay no attention to
  159. msb@sq.com                       that D-floating number behind the curtain!)"
  160. SoftQuad Inc., Toronto                          -- Chris Torek, on pasta
  161.  
  162. My text in this article is in the public domain.
  163.